#include "StdAfx.h"
#include "VSqlMetaModel.h"

// VSqlMetaModel //////////////////////////////////////////////////////////////

//
VSqlMetaModel::VSqlMetaModel(const QSqlDatabase &db,QObject *parent)
	:QAbstractItemModel(parent)
	,m_db(db)
{
	m_metaMap = new VSqlMetaMap(db);
	m_dataMap = new VSqlDataMap(m_metaMap);
	m_rootRecord = NULL;//new VSqlMetaRecord;
}

//
VSqlMetaModel::~VSqlMetaModel()
{
	//delete m_rootRecord;
	
	delete m_dataMap;
	delete m_metaMap;
}

//
void VSqlMetaModel::clear()
{
	//m_metaMap->clearMaps();

/*****
	m_rootRecord->clearChildren();
	m_rootRecord->setRecord(NULL);

	reset();
*********/	
}

//
void VSqlMetaModel::setRootRecord(const VSqlMeta &v)
{
	//m_metaMap->clearMaps();
/******
	m_rootRecord->clearChildren();
	m_rootRecord->setRecord(
		m_metaMap->record_byIdNode(v.node().idNode().value())
	);
********/

	m_rootRecord = m_metaMap->record_byIdNode(v.node().idNode().value());
	reset();

/***
	QModelIndex rootIndex = indexFromRecord(m_rootRecord);
	if (canFetchMore(rootIndex))
		fetchMore(rootIndex);
**/		
}

//
VSqlMetaRecord *VSqlMetaModel::recordFromIndex(const QModelIndex &index) const
{
	if (index.isValid()) 
	{
		VSqlMetaRecord *record = static_cast<VSqlMetaRecord*>(index.internalPointer());
		if (record) 
			return record;
	}
	return m_rootRecord;
}

//
QModelIndex VSqlMetaModel::indexFromRecord(VSqlMetaRecord *record) const
{
	return createIndex(0,0,record);
}

//
QModelIndex VSqlMetaModel::index(int row,int column,const QModelIndex &parent) const
{
	VSqlMetaRecord *parentRecord = recordFromIndex(parent);
	if (!parentRecord)
		return QModelIndex();

	if (row >= parentRecord->childCount())
		return QModelIndex();

	VSqlMetaRecord *childRecord = parentRecord->child(row);
	if (childRecord)
		return createIndex(row,column,childRecord);

	return QModelIndex();
}

//
QModelIndex VSqlMetaModel::parent(const QModelIndex &index) const
{
	if (!index.isValid())
		return QModelIndex();

	VSqlMetaRecord *childRecord = recordFromIndex(index);
	if (!childRecord)
		return QModelIndex();

	VSqlMetaRecord *parentRecord = childRecord->parent();
	if (!parentRecord)
		return QModelIndex();

	if (parentRecord == m_rootRecord)
		return QModelIndex();

	return createIndex(parentRecord->row(), 0, parentRecord);
}

//
bool VSqlMetaModel::hasChildren(const QModelIndex &parent) const
{
	VSqlMetaRecord *parentRecord = recordFromIndex(parent);
	if (!parentRecord)
		return false;

	return parentRecord->hasChildren(m_db);
}

//
bool VSqlMetaModel::canFetchMore(const QModelIndex &parent) const
{
	VSqlMetaRecord *parentRecord = recordFromIndex(parent);
	if (!parentRecord)
		return false;

	return parentRecord->hasChildren(m_db) && !parentRecord->isFetch();// childCount();
}

//
void VSqlMetaModel::fetchMore(const QModelIndex &parent)
{
	VSqlMetaRecord *parentRecord = recordFromIndex(parent);
	if (!parentRecord)
		return;

	VSqlNode node;
		node.setValues(parentRecord->node());
	QList<VSqlMetaRecord*> children = m_metaMap->children_byIdNode(node.idNode().value());

	beginInsertRows(parent, 0, children.count()-1);
		parentRecord->setIsFetch(true);//setChildren(children);
	endInsertRows();
}

//
QVariant VSqlMetaModel::headerData(int section,Qt::Orientation orientation,int role) const
{
	if (orientation == Qt::Horizontal)
	{
		switch (role)
		{
			case Qt::DisplayRole:
			{
				QString name = section < m_metaMap->columnList().count()
					? m_metaMap->columnList()[section].displayName()
					: QString("Unknown");
				return name;
			}

			case Qt::TextAlignmentRole: return int(Qt::AlignHCenter	|	Qt::AlignVCenter);
		}
	}

	return QVariant();
}

//
int VSqlMetaModel::rowCount(const QModelIndex &parent) const
{
	VSqlMetaRecord *parentRecord = recordFromIndex(parent);
	if (!parentRecord)
		return 0;

	return parentRecord->childCount();
}

//
int VSqlMetaModel::columnCount(const QModelIndex &parent) const
{
	return m_metaMap->columnList().count();
}

//
Qt::ItemFlags VSqlMetaModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
		return Qt::ItemIsEnabled;// | Qt::ItemIsDropEnabled;

	Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;

	if (index.column() == m_metaMap->columnList().colNode_refIdRec())
	{
		VSqlMetaRecord *record = recordFromIndex(index);
		if (!record)
			return f;

		VSqlItem item;
		item.setItemType(
			record->data(m_metaMap->columnList().colItemType(),m_metaMap->columnList())
		);
		if (item.isItemList())
		{
			f |= Qt::ItemIsEditable;
		}
	}

	//if (index.column() == 0)
	//	f |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;

	return f;
}

//
QVariant VSqlMetaModel::data(const QModelIndex &index,int role) const
{
	if (!index.isValid())
		return QVariant();

	VSqlMetaRecord *record = recordFromIndex(index);
	if (!record)
		return QVariant();

	int column = index.column();

	switch (role)
	{
		case Qt::TextAlignmentRole:
		{
			if (m_metaMap->columnList()[column].field().type() == QVariant::Int)
				return int(Qt::AlignRight	|	Qt::AlignVCenter);
		}
		break;

		case Qt::DisplayRole: 
		case Qt::EditRole: 
		{
			QVariant v = record->data(column,m_metaMap->columnList());
			if (v.isNull())
				return QString("<null>");
			
			if (column == m_metaMap->columnList().colDisplayName())
			{
				VSqlMeta meta(record);

				if (meta.item().isRef())
				{
					QVariant refIdItem = record->data(
						m_metaMap->columnList().colItem_refIdItem(),m_metaMap->columnList()
					);
					QString displayName = m_metaMap->item_byIdItem(refIdItem).displayName().value().toString();
					return v.toString() +  "<" + displayName + ">";
				}
				else if (meta.item().isItemList())
				{
					QVariant idTable = meta.item().refIdItem().value();
					VSqlItem itemTable = m_metaMap->itemMap()->item_byIdItem(idTable);

					QString keyNameTable = itemTable.keyName().value().toString();
					VSqlMeta metaTable = m_metaMap->meta_byKeyName(keyNameTable);

					VSqlData *data = m_dataMap->dataPtr_byMetaTable(metaTable);
					if (!data)
						return QString("<null>"); //QString() + meta.node().refIdRec().value().toString() + "<null>";

					return data->record_toDisplay(meta.node().refIdRec().value());
				}
			}
			else if (column == m_metaMap->columnList().colItemType())
			{
				return VSqlItem_maps::itemTypeToDisplayName(ESqlItemType(v.toUInt()));
			}

			return v;
		}
		
		case Qt::TextColorRole:	
		{
			if (record->data(column,m_metaMap->columnList()).isNull())
				return QColor(255,0,0);
		}
		break;
		
		case Qt::FontRole:
		{
			if (column == m_metaMap->columnList().colDisplayName())
			{
				VSqlItem item;
				item.setItemType(
					record->data(m_metaMap->columnList().colItemType(),m_metaMap->columnList())
				);

				if (item.isTable() || item.isFolder() || item.isList())
				{
					QFont font;// = QAbstractItemModel::data(index,Qt::FontRole).toFont();
						font.setPointSize(font.pointSize()+3);
						font.setItalic(true);
						font.setBold(true);
					return font;
				}
				else if (item.isRef() || item.isIdRec())
				{
					QFont font;
						//font.setPointSize(font.pointSize()+3);
						font.setItalic(true);
						//font.setBold(true);
					return font;
				}
			}
		}
		break;
	}

	return QVariant();
}

//
bool VSqlMetaModel::setData(const QModelIndex &index,const QVariant &value,int role)
{
	if (role != Qt::EditRole)
		return false;

	VSqlMetaRecord *record = recordFromIndex(index);
	if (!record)
		return false;

	QModelIndex begIndex = index;
	QModelIndex endIndex = index;

	QVariant idNode =	record->data(
		m_metaMap->columnList().colNode_idNode(),
		m_metaMap->columnList()
	);
	if (!m_metaMap->updateValue(idNode,index.column(),value))
		return false;

	emit dataChanged(begIndex,endIndex);
	return true;
}
